/***************************************************************************
 *   Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com>     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "vsf.h"
#include "usrapp.h"
#include "vsfvm_objdump.h"

struct usrapp_param_t
{
	char *src;
} static const usrapp_param =
{
	.src = "\
print(\"led toggle demo...\\r\\n\");\r\n\
const LED0_PORT = 1, LED0_PIN = 14;\r\n\
const LED1_PORT = 1, LED1_PIN = 15;\r\n\
const LED2_PORT = 1, LED2_PIN = 16;\r\n\
const LED3_PORT = 1, LED3_PIN = 17;\r\n\
const LED4_PORT = 1, LED4_PIN = 18;\r\n\
const LED_NUM = 5;\r\n\
var ledarr = array_create(2, 1, LED_NUM, 2);\r\n\
ledarr.set(0, 0, \r\n\
	LED0_PORT, LED0_PIN,\r\n\
	LED1_PORT, LED1_PIN,\r\n\
	LED2_PORT, LED2_PIN,\r\n\
	LED3_PORT, LED3_PIN,\r\n\
	LED4_PORT, LED4_PIN);\r\n\
\r\n\
led_toggle(gpio led, delay)\r\n\
{\r\n\
	led.config(GPIO_OUTPP).set();\r\n\
	while (1)\r\n\
	{\r\n\
		led.toggle();\r\n\
		timer_delayms(delay);\r\n\
	}\r\n\
}\r\n\
\r\n\
var idx = 0;\r\n\
while (idx < 5)\r\n\
{\r\n\
	thread(led_toggle, gpio_create(ledarr.get(idx, 0), ledarr.get(idx, 1)), 100 * (1 + idx));\r\n\
	idx = idx + 1;\r\n\
}\r\n\
\r\n\
while (1)\r\n\
{\r\n\
	print(\"tick = \", tickclk_getms(), \"\\r\\n\");\r\n\
	timer_delayms(1000);\r\n\
}\r\n\
",
};

static const char *vsfvmc_errcode_str[] =
{
	TO_STR(VSFVMC_ERRCODE_NONE),

	// common error
	TO_STR(VSFVMC_BUG),
	TO_STR(VSFVMC_BYTECODE_TOOLONG),
	TO_STR(VSFVMC_NOT_ENOUGH_RESOURCES),
	TO_STR(VSFVMC_FATAL_ERROR),
	TO_STR(VSFVMC_NOT_SUPPORT),

	// lexer error
	TO_STR(VSFVMC_LEXER_NOT_SUPPORT),
	TO_STR(VSFVMC_LEXER_INVALID_OP),
	TO_STR(VSFVMC_LEXER_INVALID_STRING),
	TO_STR(VSFVMC_LEXER_INVALID_ESCAPE),
	TO_STR(VSFVMC_LEXER_SYMBOL_TOO_LONG),

	// parser error
	TO_STR(VSFVMC_PARSER_UNEXPECTED_TOKEN),
	TO_STR(VSFVMC_PARSER_ALREADY_DEFINED),
	TO_STR(VSFVMC_PARSER_INVALID_CLOSURE),
	TO_STR(VSFVMC_PARSER_INVALID_EXPR),
	TO_STR(VSFVMC_PARSER_UNINITED_CONST),
	TO_STR(VSFVMC_PARSER_INVALID_CONST),
	TO_STR(VSFVMC_PARSER_DIV0),
	TO_STR(VSFVMC_PARSER_EXPECT_FUNC_PARAM),
	TO_STR(VSFVMC_PARSER_TOO_MANY_FUNC_PARAM),
	TO_STR(VSFVMC_PARSER_MEMFUNC_NOT_FOUND),

	// compiler error
	TO_STR(VSFVMC_COMPILER_INVALID_MODULE),
	TO_STR(VSFVMC_COMPILER_INVALID_FUNC),
	TO_STR(VSFVMC_COMPILER_INVALID_FUNC_PARAM),
	TO_STR(VSFVMC_COMPILER_FAIL_USRLIB),
};

static int usrapp_vm_set_bytecode(void *param, uint32_t code, uint32_t pos)
{
	struct usrapp_t *app = (struct usrapp_t *)param;
	if (pos >= dimof(app->vsfvm.token))
		return -1;

	app->vsfvm.token[pos] = code;
	return 0;
}

struct usrapp_t usrapp =
{
	.debug.uart_stream.index				= DEBUG_UART_INDEX,
	.debug.uart_stream.mode					= VSFHAL_USART_STOPBITS_1 | VSFHAL_USART_PARITY_NONE,
	.debug.uart_stream.int_priority			= 0xFF,
	.debug.uart_stream.baudrate				= 115200,

	.debug.uart_stream.stream_tx			= &usrapp.debug.stream_tx.stream,
	.debug.uart_stream.stream_rx			= &usrapp.debug.stream_rx.stream,

	.debug.stream_tx.stream.op				= &vsf_fifostream_op,
	.debug.stream_tx.mem.buffer.buffer		= (uint8_t *)&usrapp.debug.txbuff,
	.debug.stream_tx.mem.buffer.size		= sizeof(usrapp.debug.txbuff),
	.debug.stream_rx.stream.op				= &vsf_fifostream_op,
	.debug.stream_rx.mem.buffer.buffer		= (uint8_t *)&usrapp.debug.rxbuff,
	.debug.stream_rx.mem.buffer.size		= sizeof(usrapp.debug.rxbuff),

	.vsfvm.vmc.dart.op						= &vsfvmc_lexer_op_dart,
};

void usrapp_srt_init(struct usrapp_t *app)
{
	VSFSTREAM_INIT(&app->debug.stream_rx);
	VSFSTREAM_INIT(&app->debug.stream_tx);
	vsf_usart_stream_init(&app->debug.uart_stream);
	vsfdbg_init((struct vsf_stream_t *)&app->debug.stream_tx);
}

void usrapp_srt_poll(struct usrapp_t *app){}

static void usrapp_vm_compile(struct usrapp_t *app)
{
	struct vsfvmc_t *vmc = &app->vsfvm.vmc.vmc;
	int err;

	vsfdbg_prints("start compiling ..." VSFCFG_DEBUG_LINEEND);
	vsfvmc_init(vmc, &usrapp, NULL, usrapp_vm_set_bytecode);
	vsfvmc_register_lexer(vmc, &app->vsfvm.vmc.dart);
	err = vsfvmc_script(vmc, "main.dart");
	if (err < 0) goto err_return;

	err = vsfvmc_input(vmc, usrapp_param.src);
	if (err < 0)
	{
	err_return:
		err = -err;
		vsfdbg_printf("command line compile error: %s" VSFCFG_DEBUG_LINEEND,
			(err >= VSFVMC_ERRCODE_END) ? "unknwon error" : vsfvmc_errcode_str[err]);
		vsfdbg_printf("compile error around line %d column %d" VSFCFG_DEBUG_LINEEND,
			vmc->script.lexer.curctx.line + 1, vmc->script.lexer.curctx.col + 1);
	compile_end:
		vsfvmc_fini(vmc);
		return;
	}

	err = vsfvmc_input(vmc, "\xFF");
	if (err) goto compile_end;

	vsfdbg_printf("compiled OK, token number : %d" VSFCFG_DEBUG_LINEEND,
			vmc->bytecode_pos);

	app->vsfvm.token_num = vmc->bytecode_pos;
	vsfdbg_prints("objdump:" VSFCFG_DEBUG_LINEEND);
	vsfvm_objdump(app->vsfvm.token, app->vsfvm.token_num);
}

static void usrapp_vm_run(struct usrapp_t *app)
{
	struct vsfvm_t *vm = &app->vsfvm.vm.vm;
	struct vsfvm_script_t *script = &app->vsfvm.vm.script;

	memset(vm, 0, sizeof(*vm));
	memset(script, 0, sizeof(*script));
	vm->thread_pool.pool_size = 16;
	script->token = app->vsfvm.token;
	script->token_num = app->vsfvm.token_num;

	vsfvm_init(vm);
	vsfvm_script_init(vm, script);
}

void usrapp_nrt_init(struct usrapp_t *app)
{
	vsfvm_ext_register_std();
	vsfvm_ext_register_vsf();

	vsfdbg_prints("source code:" VSFCFG_DEBUG_LINEEND);
	vsfdbg_prints(usrapp_param.src);
	vsfdbg_prints(VSFCFG_DEBUG_LINEEND);

	usrapp_vm_compile(app);
	usrapp_vm_run(app);
}

void usrapp_nrt_poll(struct usrapp_t *app)
{
	vsfvm_poll(&app->vsfvm.vm.vm);
}

bool usrapp_cansleep(struct usrapp_t *app)
{
	return app->vsfvm.vm.vm.appendlist.next == NULL;
}

void usrapp_initial_init(struct usrapp_t *app){}
